#include "wxssizer.h"
#include "wxsitemresdata.h"
#include "wxssizerparentqp.h"
#include "wxsflags.h"

#include <wx/dcclient.h>
#include <logmanager.h>

using namespace wxsFlags;

namespace {
  class wxsSizerPreview: public wxPanel {
    public:
      wxsSizerPreview( wxWindow* Parent ): wxPanel( Parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ) {
        InheritAttributes();
        Connect( wxID_ANY, wxEVT_PAINT, ( wxObjectEventFunction )&wxsSizerPreview::OnPaint );
      }

    private:

      void OnPaint( M_Code_unused wxPaintEvent& event ) {
        wxPaintDC DC( this );
        int W, H;
        GetSize( &W, &H );
        DC.SetBrush( *wxTRANSPARENT_BRUSH );
        DC.SetPen( *wxRED_PEN );
        DC.DrawRectangle( 0, 0, W, H );
      }
  };
}

void wxsSizerExtra::OnEnumProperties( long _Flags ) {
  static const int Priority = 20;
  WXS_SIZERFLAGS_P( wxsSizerExtra, Flags, Priority );
  WXS_DIMENSION_P( wxsSizerExtra, Border, _T( "Border width" ), _T( "  Dialog Units" ), _T( "border" ), 0, false, Priority );
  if( !( _Flags & flMinMaxSize ) ) {
    WXS_SIZE_P( wxsSizerExtra, MinSize, _T( "Default Min size" ), _T( "Min Width" ), _T( "Min Height" ), _T( "Min size in dialog units" ), _T( "minsize" ), Priority );
  }
  WXS_LONG_P( wxsSizerExtra, Proportion, _T( "Proportion" ), _T( "option" ), 0, Priority );
}

wxString wxsSizerExtra::AllParamsCode( wxsCoderContext* Ctx ) {
  switch( Ctx->m_Language ) {
    case wxsCPP:
      return F( _T( "%ld, " ), Proportion ) +
             wxsSizerFlagsProperty::GetString( Flags ) +
             _T( ", " ) << Border.GetPixelsCode( Ctx );
    case wxsUnknownLanguage:
    default:
      wxsCodeMarks::Unknown( _T( "wxsSizerExtra::AllParamsCode" ), Ctx->m_Language );
  }
  return wxEmptyString;
}

wxsSizer::wxsSizer( wxsItemResData* Data, const wxsItemInfo* Info ):
  wxsParent( Data, Info, flVariable | flSubclass, 0, 0 ) {
  GetBaseProps()->m_IsMember = false;
}

long wxsSizer::OnGetPropertiesFlags() {
  if( !( wxsParent::OnGetPropertiesFlags() & flSource ) ) {
    return wxsParent::OnGetPropertiesFlags() & ~flVariable;
  }
  return wxsParent::OnGetPropertiesFlags();
}

void wxsSizer::OnBuildCreatingCode() {
  OnBuildSizerCreatingCode();
  bool UnknownLang = false;
  int Count = GetChildCount();
  for( int i = 0; i < Count; i++ ) {
    wxsItem* Child = GetChild( i );
    wxsSizerExtra* SizerExtra = ( wxsSizerExtra* )GetChildExtra( i );
    Child->BuildCode( GetCoderContext() );
    switch( Child->GetType() ) {
      case wxsTWidget:
      case wxsTContainer:
      case wxsTSizer:
        switch( GetLanguage() ) {
          case wxsCPP: {
            Codef( _T( "%AAdd(%o, %s);\n" ), i, SizerExtra->AllParamsCode( GetCoderContext() ).wx_str() );
            break;
          }
          case wxsUnknownLanguage:
          default: {
            UnknownLang = true;
          }
        }
        break;
      case wxsTSpacer:
        break;
      case wxsTTool:
      case wxsTInvalid:
      default:
        break;
    }
  }
  if( UnknownLang ) {
    wxsCodeMarks::Unknown( _T( "wxsSizer::OnBuildCreatingCode" ), GetLanguage() );
  }
}

void wxsSizer::OnBuildDeclarationsCode() {
  if( GetCoderFlags() & flSource ) {
    wxsItem::OnBuildDeclarationsCode();
  }
}

wxObject* wxsSizer::OnBuildPreview( wxWindow* Parent, long Flags ) {
  wxWindow* NewParent = Parent;
  if( !( Flags & pfExact ) ) {
    NewParent = new wxsSizerPreview( Parent );
  }
  wxSizer* Sizer = OnBuildSizerPreview( NewParent );
  int Count = GetChildCount();
  for( int i = 0; i < Count; i++ ) {
    wxsItem* Child = GetChild( i );
    wxsSizerExtra* SizerExtra = ( wxsSizerExtra* )GetChildExtra( i );
    wxObject* ChildPreview = Child->BuildPreview( NewParent, Flags );
    if( !ChildPreview ) {
      continue;
    }
    wxSizer* ChildAsSizer = wxDynamicCast( ChildPreview, wxSizer );
    wxWindow* ChildAsWindow = wxDynamicCast( ChildPreview, wxWindow );
    wxSizerItem* ChildAsItem = wxDynamicCast( ChildPreview, wxSizerItem );
    if( ChildAsSizer ) {
      Sizer->Add( ChildAsSizer, SizerExtra->Proportion,
                  wxsSizerFlagsProperty::GetWxFlags( SizerExtra->Flags ),
                  SizerExtra->Border.GetPixels( Parent ) );
    } else if( ChildAsWindow ) {
      Sizer->Add( ChildAsWindow, SizerExtra->Proportion,
                  wxsSizerFlagsProperty::GetWxFlags( SizerExtra->Flags ),
                  SizerExtra->Border.GetPixels( Parent ) );
    } else if( ChildAsItem ) {
      ChildAsItem->SetProportion( SizerExtra->Proportion );
      ChildAsItem->SetFlag( wxsSizerFlagsProperty::GetWxFlags( SizerExtra->Flags ) );
      ChildAsItem->SetBorder( SizerExtra->Border.GetPixels( Parent ) );
      Sizer->Add( ChildAsItem );
    }
  }
  if( !( Flags & pfExact ) ) {
    NewParent->SetSizer( Sizer );
    if( !GetChildCount() ) {
      NewParent->SetInitialSize( wxSize( 20, 20 ) );
      NewParent->SetSizeHints( 20, 20 );
      NewParent->SetSize( wxSize( 20, 20 ) );
    } else {
      Sizer->Fit( NewParent );
      Sizer->SetSizeHints( NewParent );
    }
    return NewParent;
  }
  return Sizer;
}

wxsPropertyContainer* wxsSizer::OnBuildExtra() {
  return new wxsSizerExtra();
}

void wxsSizer::OnAddChildQPP( wxsItem* Child, wxsAdvQPP* QPP ) {
  wxsParent::OnAddChildQPP( Child, QPP );
  int Index = GetChildIndex( Child );
  if( Index >= 0 ) {
    QPP->Register( new wxsSizerParentQP( QPP, ( wxsSizerExtra* )GetChildExtra( Index ) ), _T( "Sizer" ) );
  }
}

bool wxsSizer::OnXmlReadChild( TiXmlElement* Elem, bool IsXRC, bool IsExtra ) {
  if( cbC2U( Elem->Attribute( "class" ) ) == _T( "spacer" ) ) {
    wxsItem* Item = wxsItemFactory::Build( _T( "Spacer" ), GetResourceData() );
    if( !AddChild( Item ) ) {
      delete Item;
      return false;
    }
    RestoreExtraData( GetChildCount() - 1, Elem );
    return Item->XmlRead( Elem, IsXRC, IsExtra );
  }
  return wxsParent::OnXmlReadChild( Elem, IsXRC, IsExtra );
}

bool wxsSizer::OnXmlWriteChild( int Index, TiXmlElement* Elem, bool IsXRC, bool IsExtra ) {
  wxsItem* Child = GetChild( Index );
  if( Child->GetType() == wxsTSpacer ) {
    StoreExtraData( Index, Elem );
    bool Ret = Child->XmlWrite( Elem, IsXRC, IsExtra );
    Elem->SetAttribute( "class", "spacer" );
    return Ret;
  }
  return wxsParent::OnXmlWriteChild( Index, Elem, IsXRC, IsExtra );
}

wxString wxsSizer::OnXmlGetExtraObjectClass() {
  return _T( "sizeritem" );
}

void wxsSizer::OnEnumItemProperties( long Flags ) {
  OnEnumSizerProperties( Flags );
}

void wxsSizer::OnAddItemQPP( wxsAdvQPP* QPP ) {
  OnAddSizerQPP( QPP );
}
